"""
@author: forward
@contact: 1@qq.com
@software: garner
@file: code.py
@time: 2021/11/25 17:09
"""

from typing import List

from sqlalchemy import BinaryExpression, delete, func, select, update

from forward.api.admin.schemas.lucky.code import CodeDetailOutSchema
from forward.common.enums import CodeStatusEnum
from forward.dependencies.database import db
from forward.model.orm.base import BaseORM
from forward.model.schemas.lucky.code import CodeOutSchema
from forward.model.tables.activity import ActivityModel, CodeModel, PrizeModel
from forward.model.tables.merchant import MerchantModel
from forward.utils.page_utils import PageSchema, PageUtils


class CodeORM(BaseORM[CodeOutSchema,]):
    """code orm

    Args:
        BaseORM (_type_): _description_
    """

    MODEL = CodeModel
    OUT_SCHEMA = CodeOutSchema

    async def lists(
        self,
        where: List[BinaryExpression] | None = None,
        page_num: int = 1,
        page_size: int = 15,
        **kwargs
    ) -> PageSchema[CodeDetailOutSchema]:
        """
        code 分页
        """
        where_conditions = []
        if where is not None:
            where_conditions.extend(where)
        statement = (
            select(
                CodeModel,
                PrizeModel.name.label("prize_name"),
                MerchantModel.name.label("merchant_name"),
                ActivityModel.title.label("activity_title"),
            )
            .where(*where_conditions)
            .outerjoin(PrizeModel, CodeModel.prize_id == PrizeModel.id)
            .outerjoin(ActivityModel, CodeModel.activity_id == ActivityModel.id)
            .outerjoin(MerchantModel, ActivityModel.merchant_id == MerchantModel.id)
            .order_by(CodeModel.code_id.asc())
        )
        pagination = await PageUtils.paginate(
            db=db,
            query=statement,
            page_num=page_num,
            page_size=page_size,
            schema=CodeDetailOutSchema,
            **kwargs
        )
        return pagination

    async def get_bind_activity_count(self, code_batch_id: int) -> int:
        statement = (
            select(func.count(func.distinct(CodeModel.activity_id)))
            .where(CodeModel.code_batch_id == code_batch_id)
            .where(CodeModel.activity_id.is_not(None))
        )
        count = await db.fetch_val(statement)
        return count

    async def delete_by_code_batch_id(self, code_batch_id: int):
        statement = delete(CodeModel).where(CodeModel.code_batch_id == code_batch_id)
        return await db.execute(statement)

    async def reset_codes(self, activity_id: int):
        """重置码号，将已绑定活动的码号改为未使用"""
        statement = (
            update(CodeModel)
            .where(
                CodeModel.activity_id == activity_id,
                CodeModel.status == CodeStatusEnum.BOUND.value,
            )
            .values(
                {
                    "activity_id": None,
                    "prize_id": None,
                    "prize_index": None,
                    "draw_time": None,
                    "status": CodeStatusEnum.UNUSED.value,
                }
            )
        )
        record = await db.execute(statement)
        return record
